home *** CD-ROM | disk | FTP | other *** search
/ Cream of the Crop 26 / Cream of the Crop 26.iso / program / nasm095s.zip / OUTAS86.C < prev    next >
C/C++ Source or Header  |  1997-07-27  |  15KB  |  550 lines

  1. /* outas86.c    output routines for the Netwide Assembler to produce
  2.  *        Linux as86 (bin86-0.3) object files
  3.  *
  4.  * The Netwide Assembler is copyright (C) 1996 Simon Tatham and
  5.  * Julian Hall. All rights reserved. The software is
  6.  * redistributable under the licence given in the file "Licence"
  7.  * distributed in the NASM archive.
  8.  */
  9.  
  10. #include <stdio.h>
  11. #include <stdlib.h>
  12. #include <string.h>
  13. #include <ctype.h>
  14.  
  15. #include "nasm.h"
  16. #include "nasmlib.h"
  17. #include "outform.h"
  18.  
  19. #ifdef OF_AS86
  20.  
  21. struct Piece {
  22.     struct Piece *next;
  23.     int type;                   /* 0 = absolute, 1 = seg, 2 = sym */
  24.     long offset;               /* relative offset */
  25.     int number;                   /* symbol/segment number (4=bss) */
  26.     long bytes;                   /* size of reloc or of absolute data */
  27.     int relative;               /* TRUE or FALSE */
  28. };
  29.  
  30. struct Symbol {
  31.     long strpos;               /* string table position of name */
  32.     int flags;                   /* symbol flags */
  33.     int segment;               /* 4=bss at this point */
  34.     long value;                   /* address, or COMMON variable size */
  35. };
  36.  
  37. /*
  38.  * Section IDs - used in Piece.number and Symbol.segment.
  39.  */
  40. #define SECT_TEXT 0               /* text section */
  41. #define SECT_DATA 3               /* data section */
  42. #define SECT_BSS 4               /* bss section */
  43.  
  44. /*
  45.  * Flags used in Symbol.flags.
  46.  */
  47. #define SYM_ENTRY (1<<8)
  48. #define SYM_EXPORT (1<<7)
  49. #define SYM_IMPORT (1<<6)
  50. #define SYM_ABSOLUTE (1<<4)
  51.  
  52. struct Section {
  53.     struct SAA *data;
  54.     unsigned long datalen, size, len;
  55.     long index;
  56.     struct Piece *head, *last, **tail;
  57. };
  58.  
  59. static char as86_module[FILENAME_MAX];
  60.  
  61. static struct Section stext, sdata;
  62. static unsigned long bsslen;
  63. static long bssindex;
  64.  
  65. static struct SAA *syms;
  66. static unsigned long nsyms;
  67.  
  68. static struct RAA *bsym;
  69.  
  70. static struct SAA *strs;
  71. static unsigned long strslen;
  72.  
  73. static int as86_reloc_size;
  74.  
  75. static FILE *as86fp;
  76. static efunc error;
  77.  
  78. static void as86_write(void);
  79. static void as86_write_section (struct Section *, int);
  80. static int as86_add_string (char *name);
  81. static void as86_sect_write(struct Section *, unsigned char *, unsigned long);
  82.  
  83. static void as86_init(FILE *fp, efunc errfunc, ldfunc ldef) {
  84.     as86fp = fp;
  85.     error = errfunc;
  86.     (void) ldef;               /* placate optimisers */
  87.     stext.data = saa_init(1L); stext.datalen = 0L;
  88.     stext.head = stext.last = NULL;
  89.     stext.tail = &stext.head;
  90.     sdata.data = saa_init(1L); sdata.datalen = 0L;
  91.     sdata.head = sdata.last = NULL;
  92.     sdata.tail = &sdata.head;
  93.     bsslen =
  94.     stext.len = stext.datalen = stext.size =
  95.     sdata.len = sdata.datalen = sdata.size = 0;
  96.     stext.index = seg_alloc();
  97.     sdata.index = seg_alloc();
  98.     bssindex = seg_alloc();
  99.     syms = saa_init((long)sizeof(struct Symbol));
  100.     nsyms = 0;
  101.     bsym = raa_init();
  102.     strs = saa_init(1L);
  103.     strslen = 0;
  104.  
  105.     as86_add_string (as86_module);
  106. }
  107.  
  108. static void as86_cleanup(void) {
  109.     struct Piece *p;
  110.  
  111.     as86_write();
  112.     fclose (as86fp);
  113.     saa_free (stext.data);
  114.     while (stext.head) {
  115.     p = stext.head;
  116.     stext.head = stext.head->next;
  117.     nasm_free (p);
  118.     }
  119.     saa_free (sdata.data);
  120.     while (sdata.head) {
  121.     p = sdata.head;
  122.     sdata.head = sdata.head->next;
  123.     nasm_free (p);
  124.     }
  125.     saa_free (syms);
  126.     raa_free (bsym);
  127.     saa_free (strs);
  128. }
  129.  
  130. static long as86_section_names (char *name, int pass, int *bits) {
  131.     /*
  132.      * Default is 16 bits.
  133.      */
  134.     if (!name)
  135.     *bits = 16;
  136.  
  137.     if (!name)
  138.     return stext.index;
  139.  
  140.     if (!strcmp(name, ".text"))
  141.     return stext.index;
  142.     else if (!strcmp(name, ".data"))
  143.     return sdata.index;
  144.     else if (!strcmp(name, ".bss"))
  145.     return bssindex;
  146.     else
  147.     return NO_SEG;
  148. }
  149.  
  150. static int as86_add_string (char *name) {
  151.     int pos = strslen;
  152.     int length = strlen(name);
  153.  
  154.     saa_wbytes (strs, name, (long)(length+1));
  155.     strslen += 1+length;
  156.  
  157.     return pos;
  158. }
  159.  
  160. static void as86_deflabel (char *name, long segment, long offset,
  161.                int is_global) {
  162.     struct Symbol *sym;
  163.  
  164.     if (name[0] == '.' && name[1] == '.' && name[2] != '@') {
  165.     error (ERR_NONFATAL, "unrecognised special symbol `%s'", name);
  166.     return;
  167.     }
  168.  
  169.     sym = saa_wstruct (syms);
  170.  
  171.     sym->strpos = as86_add_string (name);
  172.     sym->flags = 0;
  173.     if (segment == NO_SEG)
  174.     sym->flags |= SYM_ABSOLUTE, sym->segment = 0;
  175.     else if (segment == stext.index)
  176.     sym->segment = SECT_TEXT;
  177.     else if (segment == sdata.index)
  178.     sym->segment = SECT_DATA;
  179.     else if (segment == bssindex)
  180.     sym->segment = SECT_BSS;
  181.     else {
  182.     sym->flags |= SYM_IMPORT;
  183.     sym->segment = 15;
  184.     }
  185.  
  186.     if (is_global == 2)
  187.     sym->segment = 3;       /* already have IMPORT */
  188.  
  189.     if (is_global && !(sym->flags & SYM_IMPORT))
  190.     sym->flags |= SYM_EXPORT;
  191.  
  192.     sym->value = offset;
  193.  
  194.     /*
  195.      * define the references from external-symbol segment numbers
  196.      * to these symbol records.
  197.      */
  198.     if (segment != NO_SEG && segment != stext.index &&
  199.     segment != sdata.index && segment != bssindex)
  200.     bsym = raa_write (bsym, segment, nsyms);
  201.  
  202.     nsyms++;
  203. }
  204.  
  205. static void as86_add_piece (struct Section *sect, int type, long offset,
  206.                 long segment, long bytes, int relative) {
  207.     struct Piece *p;
  208.  
  209.     sect->len += bytes;
  210.  
  211.     if (type == 0 && sect->last && sect->last->type == 0) {
  212.     sect->last->bytes += bytes;
  213.     return;
  214.     }
  215.  
  216.     p = sect->last = *sect->tail = nasm_malloc(sizeof(struct Piece));
  217.     sect->tail = &p->next;
  218.     p->next = NULL;
  219.  
  220.     p->type = type;
  221.     p->offset = offset;
  222.     p->bytes = bytes;
  223.     p->relative = relative;
  224.  
  225.     if (type == 1 && segment == stext.index)
  226.     p->number = SECT_TEXT;
  227.     else if (type == 1 && segment == sdata.index)
  228.     p->number = SECT_DATA;
  229.     else if (type == 1 && segment == bssindex)
  230.     p->number = SECT_BSS;
  231.     else if (type == 1)
  232.     p->number = raa_read (bsym, segment), p->type = 2;
  233. }
  234.  
  235. static void as86_out (long segto, void *data, unsigned long type,
  236.               long segment, long wrt) {
  237.     struct Section *s;
  238.     long realbytes = type & OUT_SIZMASK;
  239.     long offset;
  240.     unsigned char mydata[4], *p;
  241.  
  242.     if (wrt != NO_SEG) {
  243.     wrt = NO_SEG;               /* continue to do _something_ */
  244.     error (ERR_NONFATAL, "WRT not supported by as86 output format");
  245.     }
  246.  
  247.     type &= OUT_TYPMASK;
  248.  
  249.     /*
  250.      * handle absolute-assembly (structure definitions)
  251.      */
  252.     if (segto == NO_SEG) {
  253.     if (type != OUT_RESERVE)
  254.         error (ERR_NONFATAL, "attempt to assemble code in [ABSOLUTE]"
  255.            " space");
  256.     return;
  257.     }
  258.  
  259.     if (segto == stext.index)
  260.     s = &stext;
  261.     else if (segto == sdata.index)
  262.     s = &sdata;
  263.     else if (segto == bssindex)
  264.     s = NULL;
  265.     else {
  266.     error(ERR_WARNING, "attempt to assemble code in"
  267.           " segment %d: defaulting to `.text'", segto);
  268.     s = &stext;
  269.     }
  270.  
  271.     if (!s && type != OUT_RESERVE) {
  272.     error(ERR_WARNING, "attempt to initialise memory in the"
  273.           " BSS section: ignored");
  274.     if (type == OUT_REL2ADR)
  275.         realbytes = 2;
  276.     else if (type == OUT_REL4ADR)
  277.         realbytes = 4;
  278.     bsslen += realbytes;
  279.     return;
  280.     }
  281.  
  282.     if (type == OUT_RESERVE) {
  283.     if (s) {
  284.         error(ERR_WARNING, "uninitialised space declared in"
  285.           " %s section: zeroing",
  286.           (segto == stext.index ? "code" : "data"));
  287.         as86_sect_write (s, NULL, realbytes);
  288.         as86_add_piece (s, 0, 0L, 0L, realbytes, 0);
  289.     } else
  290.         bsslen += realbytes;
  291.     } else if (type == OUT_RAWDATA) {
  292.     if (segment != NO_SEG)
  293.         error(ERR_PANIC, "OUT_RAWDATA with other than NO_SEG");
  294.     as86_sect_write (s, data, realbytes);
  295.     as86_add_piece (s, 0, 0L, 0L, realbytes, 0);
  296.     } else if (type == OUT_ADDRESS) {
  297.     if (segment != NO_SEG) {
  298.         if (segment % 2) {
  299.         error(ERR_NONFATAL, "as86 format does not support"
  300.               " segment base references");
  301.         } else{
  302.         offset = * (long *) data;
  303.         as86_add_piece (s, 1, offset, segment, realbytes, 0);
  304.         }
  305.     } else {
  306.         p = mydata;
  307.         WRITELONG (p, * (long *) data);
  308.         as86_sect_write (s, data, realbytes);
  309.         as86_add_piece (s, 0, 0L, 0L, realbytes, 0);
  310.     }
  311.     } else if (type == OUT_REL2ADR) {
  312.     if (segment == segto)
  313.         error(ERR_PANIC, "intra-segment OUT_REL2ADR");
  314.     if (segment != NO_SEG) {
  315.         if (segment % 2) {
  316.         error(ERR_NONFATAL, "as86 format does not support"
  317.               " segment base references");
  318.         } else {
  319.         offset = * (long *) data;
  320.         as86_add_piece (s, 1, offset-realbytes+2, segment, 2L, 1);
  321.         }
  322.     }
  323.     } else if (type == OUT_REL4ADR) {
  324.     if (segment == segto)
  325.         error(ERR_PANIC, "intra-segment OUT_REL4ADR");
  326.     if (segment != NO_SEG) {
  327.         if (segment % 2) {
  328.         error(ERR_NONFATAL, "as86 format does not support"
  329.               " segment base references");
  330.         } else {
  331.         offset = * (long *) data;
  332.         as86_add_piece (s, 1, offset-realbytes+4, segment, 4L, 1);
  333.         }
  334.     }
  335.     }
  336. }
  337.  
  338. static void as86_write(void) {
  339.     int i;
  340.     long symlen, seglen, segsize;
  341.  
  342.     /*
  343.      * First, go through the symbol records working out how big
  344.      * each will be. Also fix up BSS references at this time, and
  345.      * set the flags words up completely.
  346.      */
  347.     symlen = 0;
  348.     saa_rewind (syms);
  349.     for (i = 0; i < nsyms; i++) {
  350.     struct Symbol *sym = saa_rstruct (syms);
  351.     if (sym->segment == SECT_BSS)
  352.         sym->segment = SECT_DATA, sym->value += sdata.len;
  353.     sym->flags |= sym->segment;
  354.     if (sym->value == 0)
  355.         sym->flags |= 0 << 14, symlen += 4;
  356.     else if (sym->value >= 0 && sym->value <= 255)
  357.         sym->flags |= 1 << 14, symlen += 5;
  358.     else if (sym->value >= 0 && sym->value <= 65535L)
  359.         sym->flags |= 2 << 14, symlen += 6;
  360.     else
  361.         sym->flags |= 3 << 14, symlen += 8;
  362.     }
  363.  
  364.     /*
  365.      * Now do the same for the segments, and get the segment size
  366.      * descriptor word at the same time.
  367.      */
  368.     seglen = segsize = 0;
  369.     if ((unsigned long) stext.len > 65535L)
  370.     segsize |= 0x03000000L, seglen += 4;
  371.     else
  372.     segsize |= 0x02000000L, seglen += 2;
  373.     if ((unsigned long) sdata.len > 65535L)
  374.     segsize |= 0xC0000000L, seglen += 4;
  375.     else
  376.     segsize |= 0x80000000L, seglen += 2;
  377.  
  378.     /*
  379.      * Emit the as86 header.
  380.      */
  381.     fwritelong (0x000186A3L, as86fp);
  382.     fputc (0x2A, as86fp);
  383.     fwritelong (27+symlen+seglen+strslen, as86fp);   /* header length */
  384.     fwritelong (stext.len+sdata.len, as86fp);
  385.     fwriteshort (strslen, as86fp);
  386.     fwriteshort (0, as86fp);           /* class = revision = 0 */
  387.     fwritelong (0x55555555L, as86fp);   /* segment max sizes: always this */
  388.     fwritelong (segsize, as86fp);      /* segment size descriptors */
  389.     if (segsize & 0x01000000L)
  390.     fwritelong (stext.len, as86fp);
  391.     else
  392.     fwriteshort (stext.len, as86fp);
  393.     if (segsize & 0x40000000L)
  394.     fwritelong (sdata.len, as86fp);
  395.     else
  396.     fwriteshort (sdata.len, as86fp);
  397.     fwriteshort (nsyms, as86fp);
  398.  
  399.     /*
  400.      * Write the symbol table.
  401.      */
  402.     saa_rewind (syms);
  403.     for (i = 0; i < nsyms; i++) {
  404.     struct Symbol *sym = saa_rstruct (syms);
  405.     fwriteshort (sym->strpos, as86fp);
  406.     fwriteshort (sym->flags, as86fp);
  407.     switch (sym->flags & (3<<14)) {
  408.       case 0<<14: break;
  409.       case 1<<14: fputc (sym->value, as86fp); break;
  410.       case 2<<14: fwriteshort (sym->value, as86fp); break;
  411.       case 3<<14: fwritelong (sym->value, as86fp); break;
  412.     }
  413.     }
  414.  
  415.     /*
  416.      * Write out the string table.
  417.      */
  418.     saa_fpwrite (strs, as86fp);
  419.  
  420.     /*
  421.      * Write the program text.
  422.      */
  423.     as86_reloc_size = -1;
  424.     as86_write_section (&stext, SECT_TEXT);
  425.     as86_write_section (&sdata, SECT_DATA);
  426.     fputc (0, as86fp);               /* termination */
  427. }
  428.  
  429. static void as86_set_rsize (int size) {
  430.     if (as86_reloc_size != size) {
  431.     switch (as86_reloc_size = size) {
  432.       case 1: fputc (0x01, as86fp); break;   /* shouldn't happen */
  433.       case 2: fputc (0x02, as86fp); break;
  434.       case 4: fputc (0x03, as86fp); break;
  435.       default: error (ERR_PANIC, "bizarre relocation size %d", size);
  436.     }
  437.     }
  438. }
  439.  
  440. static void as86_write_section (struct Section *sect, int index) {
  441.     struct Piece *p;
  442.     unsigned long s;
  443.     long length;
  444.  
  445.     fputc (0x20+index, as86fp);           /* select the right section */
  446.  
  447.     saa_rewind (sect->data);
  448.  
  449.     for (p = sect->head; p; p = p->next)
  450.     switch (p->type) {
  451.       case 0:
  452.         /*
  453.          * Absolute data. Emit it in chunks of at most 64
  454.          * bytes.
  455.          */
  456.         length = p->bytes;
  457.         do {
  458.         char buf[64];
  459.         long tmplen = (length > 64 ? 64 : length);
  460.         fputc (0x40 | (tmplen & 0x3F), as86fp);
  461.         saa_rnbytes (sect->data, buf, tmplen);
  462.         fwrite (buf, 1, tmplen, as86fp);
  463.         length -= tmplen;
  464.         } while (length > 0);
  465.         break;
  466.       case 1:
  467.         /*
  468.          * A segment-type relocation. First fix up the BSS.
  469.          */
  470.         if (p->number == SECT_BSS)
  471.         p->number = SECT_DATA, p->offset += sdata.len;
  472.         as86_set_rsize (p->bytes);
  473.         fputc (0x80 | (p->relative ? 0x20 : 0) | p->number, as86fp);
  474.         if (as86_reloc_size == 2)
  475.         fwriteshort (p->offset, as86fp);
  476.         else
  477.         fwritelong (p->offset, as86fp);
  478.         break;
  479.       case 2:
  480.         /*
  481.          * A symbol-type relocation.
  482.          */
  483.         as86_set_rsize (p->bytes);
  484.         s = p->offset;
  485.         if (s > 65535L)
  486.         s = 3;
  487.         else if (s > 255)
  488.         s = 2;
  489.         else if (s > 0)
  490.         s = 1;
  491.         else
  492.         s = 0;
  493.         fputc (0xC0 |
  494.            (p->relative ? 0x20 : 0) |
  495.            (p->number > 255 ? 0x04 : 0) | s, as86fp);
  496.         if (p->number > 255)
  497.         fwriteshort (p->number, as86fp);
  498.         else
  499.         fputc (p->number, as86fp);
  500.         switch ((int)s) {
  501.           case 0: break;
  502.           case 1: fputc (p->offset, as86fp); break;
  503.           case 2: fwriteshort (p->offset, as86fp); break;
  504.           case 3: fwritelong (p->offset, as86fp); break;
  505.         }
  506.         break;
  507.     }
  508. }
  509.  
  510. static void as86_sect_write (struct Section *sect,
  511.                  unsigned char *data, unsigned long len) {
  512.     saa_wbytes (sect->data, data, len);
  513.     sect->datalen += len;
  514. }
  515.  
  516. static long as86_segbase (long segment) {
  517.     return segment;
  518. }
  519.  
  520. static int as86_directive (char *directive, char *value, int pass) {
  521.     return 0;
  522. }
  523.  
  524. static void as86_filename (char *inname, char *outname, efunc error) {
  525.     char *p;
  526.  
  527.     if ( (p = strrchr (inname, '.')) != NULL) {
  528.     strncpy (as86_module, inname, p-inname);
  529.     as86_module[p-inname] = '\0';
  530.     } else
  531.     strcpy (as86_module, inname);
  532.  
  533.     standard_extension (inname, outname, ".o", error);
  534. }
  535.  
  536. struct ofmt of_as86 = {
  537.     "Linux as86 (bin86 version 0.3) object files",
  538.     "as86",
  539.     as86_init,
  540.     as86_out,
  541.     as86_deflabel,
  542.     as86_section_names,
  543.     as86_segbase,
  544.     as86_directive,
  545.     as86_filename,
  546.     as86_cleanup
  547. };
  548.  
  549. #endif /* OF_AS86 */
  550.